package org.melanesia.test;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;

import java.math.BigDecimal;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;
import org.melanesia.converters.JavaToJavaConverter;
import org.melanesia.converters.JavaToJdbcConverter;
import org.melanesia.converters.TypeConverter;
import org.melanesia.converters.exceptions.ConversionException;
import org.melanesia.converters.java.DateToDateConverter;
import org.melanesia.sql.SQLBuilder;

public class CollectionConversion {

    private Connection connection;
    private SQLBuilder sqlBuilder;

    @Before
    public void init() throws SQLException {
        connection = DriverManager.getConnection(
                "jdbc:oracle:thin:@localhost:1521:xe", "melanesia", "melanesia");
        connection.setAutoCommit(false);

        sqlBuilder = new SQLBuilder(connection);
    }

    @Test
    public void arrayConversionExact() {

        TypeConverter converter = new TypeConverter();

        converter.registerConverter(Integer[].class, BigDecimal[].class, new JavaToJavaConverter() {

            @Override
            public Object convert(final TypeConverter typeConverterContext, final Object value) throws ConversionException {
                throw new ConversionException("Found!");
            }

        });

        converter.registerConverter(Number[].class, BigDecimal[].class, new JavaToJavaConverter() {

            @Override
            public Object convert(final TypeConverter typeConverterContext, final Object value) throws ConversionException {
                throw new ConversionException("Wrong!");
            }

        });

        try {
            JavaToJavaConverter cv = converter.findJavaToJavaConverter(Integer[].class, BigDecimal[].class);
            cv.convert(converter, new Integer[] {10, 11, 12});

            fail("Exception not thrown");
        } catch (ConversionException ex) {
            assertEquals("Found!", ex.getMessage());
        }
    }


    @Test
    public void arrayConversionWithSuperclassConverter() {

        TypeConverter converter = new TypeConverter();

        converter.registerConverter(Object[].class, BigDecimal[].class, new JavaToJavaConverter() {

            @Override
            public Object convert(final TypeConverter typeConverterContext, final Object value) throws ConversionException {
                throw new ConversionException("Found!");
            }

        });

        try {
            JavaToJavaConverter cv = converter.findJavaToJavaConverter(Integer[].class, BigDecimal[].class);
            cv.convert(converter, new Integer[] {10, 11, 12});

            fail("Exception not thrown");
        } catch (ConversionException ex) {
            assertEquals("Found!", ex.getMessage());
        }
    }

    @Test
    public void explicitConverters() {

        final Map<String, String> asserts = new HashMap<String, String>();

        java.util.Date d = sqlBuilder.createQuery("SELECT SYSDATE AS JAVA_DATE FROM DUAL WHERE :PARAM = 1")
            .setParameter("PARAM", 1, new JavaToJdbcConverter() {

                @Override
                public int getJdbcType(final TypeConverter typeConverterContext) {
                    return Types.NUMERIC;
                }

                @Override
                public Object convert(final TypeConverter typeConverterContext, final Object value, final Statement stmt, final String parameterName) throws ConversionException {
                    asserts.put("JDBC", "called");
                    return value;
                }
            })
            .setColumnConverter("JAVA_DATE", new JavaToJavaConverter() {

                @Override
                public Object convert(final TypeConverter typeConverterContext, final Object value) throws ConversionException {
                    asserts.put("JAVA", "called");
                    return new DateToDateConverter(java.util.Date.class).convert(typeConverterContext, value);
                }
            })
            .executeSingle(java.util.Date.class, "JAVA_DATE");


        assertEquals("called", asserts.get("JDBC"));
        assertEquals("called", asserts.get("JAVA"));

    }


}
